/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jackrabbit.node;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.ConstraintViolationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class NodeCopier {
protected static Log log=LogFactory.getLog(NodeCopier.class);
/**
* Copy node with srcPath from one repository to another using the export and import functions
* @param srcSession
* @param destSession
* @param srcPath
* @param destPath
* @param relPath
* @param createNodeType
* @throws RepositoryException
* @throws IOException
*/
public static void copy(Session srcSession, Session destSession, String srcPath, String destPath, boolean addNodeType) throws RepositoryException, IOException {
createNodes(srcSession, destSession, destPath, addNodeType);
copy(srcSession, destSession, srcPath, destPath, "", false, addNodeType);
}
/**
* Copy node with srcPath from one repository to another using the export and import functions
* @param srcSession
* @param destSession
* @param srcPath
* @param destPath
* @param relPath
* @param noRecurse - Boolean to indicate whether to copy the node recursively
* @param createNodeType
* @throws RepositoryException
* @throws IOException
*/
public static void copy(Session srcSession, Session destSession, String srcPath, String destPath, String relPath, boolean noRecurse, boolean addNodeType) throws RepositoryException, IOException {
if (!srcSession.nodeExists(srcPath)) {
log.error(srcPath+ " does not exist");
return;
}
ByteArrayOutputStream out=new ByteArrayOutputStream();
ByteArrayInputStream in=null;
String nodeName=srcPath.replaceAll(".*/(\\w+)$", "$1");
try {
srcSession.exportSystemView(srcPath+relPath, out, true, noRecurse);
in=new ByteArrayInputStream(out.toByteArray());
try {
if (!relPath.isEmpty()) {
relPath="/"+nodeName+relPath.substring(0, relPath.lastIndexOf("/"));
createNodes(srcSession, destSession, srcPath, destPath, relPath, addNodeType);
}
destSession.importXML(destPath+relPath, in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
destSession.save();
log.info(srcSession.getWorkspace().getName()+" workspace: node copied from "+srcPath+" to "+destPath+relPath+ " with relative path " + relPath);
} catch (ItemNotFoundException e) {
//do nothing as some references may not exist yet
} catch (ConstraintViolationException e) {
//do nothing as some references may not exist yet
}
} finally {
if (in!=null) {
IOUtils.closeQuietly(in);
}
IOUtils.closeQuietly(out);
}
}
/**
* Copy node with srcPath from one repository to another using the export and import functions by first partitioning node to subnodes of size less than
* limit before exporting
* @param srcSession
* @param destSession
* @param srcPath
* @param destPath
* @param limit - size of a node in the partition
* @param createNodeType
* @throws RepositoryException
* @throws IOException
*/
public static void copy(Session srcSession, Session destSession, String srcPath, String destPath, long limit, boolean addNodeType) throws RepositoryException, IOException {
if (!srcSession.nodeExists(srcPath)) {
log.error(srcPath+ " does not exist");
return;
}
createNodes(srcSession, destSession, destPath, addNodeType);
Node node=srcSession.getNode(srcPath);
int srcPathLength=srcPath.length();
NodePartitioner partitioner=new NodeSizePartitioner(limit);
Set<Map.Entry<String, Boolean>> descendants=partitioner.partition(node);
for (Map.Entry<String, Boolean> entry: descendants) {
String relPath=entry.getKey().substring(srcPathLength);
copy(srcSession, destSession, srcPath, destPath, relPath, entry.getValue(), addNodeType);
}
}
/**
* create nodes along path in destination workspace with node type from source workspace if they do not exist
* @param srcSession
* @param destSession
* @param path
* @param addNodeType whether to create
* @throws RepositoryException
*/
private static void createNodes(Session srcSession, Session destSession, String path, boolean addNodeType) throws RepositoryException {
if (destSession.nodeExists(path))
return;
Node parent=destSession.getRootNode();
String cumuPath="";
String[] nodeNames=path.split("/");
Node child;
for (int i=0;i<nodeNames.length;i++) {
if (nodeNames[i].isEmpty())
continue;
cumuPath+="/"+nodeNames[i];
if (!parent.hasNode(nodeNames[i])) {
if (addNodeType && srcSession.itemExists(cumuPath))
child=parent.addNode(nodeNames[i], srcSession.getNode(cumuPath).getPrimaryNodeType().getName());
else
child=parent.addNode(nodeNames[i]);
} else {
child=parent.getNode(nodeNames[i]);
}
parent=child;
}
destSession.save();
}
/**
* create nodes along relPath in destination workspace with node type from source workspace if they do not exist
* @param srcSession
* @param destSession
* @param srcPath
* @param destPath
* @param relPath
* @param addNodeType
* @throws RepositoryException
*/
private static void createNodes(Session srcSession, Session destSession, String srcPath, String destPath, String relPath, boolean addNodeType) throws RepositoryException {
//srcPath without last node name
String cumuPath=srcPath.replaceAll("(.*)/\\w+$", "$1");
//log.info("dest path: "+destPath+relPath);
if (destSession.nodeExists(destPath+relPath))
return;
String[] nodeNames=relPath.split("/");
Node parent=destSession.getNode(destPath);
for (int i=0;i<nodeNames.length;i++) {
String nodeName=nodeNames[i];
if (nodeName.isEmpty())
continue;
cumuPath+="/"+nodeName;
if (!parent.hasNode(nodeName)) {
//log.info(srcSession.getWorkspace().getName()+" adding node: "+nodeName+" to "+parent.getPath());
if (addNodeType && srcSession.itemExists(cumuPath))
parent.addNode(nodeName, srcSession.getNode(cumuPath).getPrimaryNodeType().getName());
else
parent.addNode(nodeName);
}
parent=parent.getNode(nodeName);
}
destSession.save();
}
}